home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / devs / agnet / device.c < prev    next >
C/C++ Source or Header  |  1994-02-27  |  36KB  |  1,390 lines

  1. RCS_ID_C="$Id: device.c,v 4.1 1994/02/25 14:55:44 ppessi Exp $";
  2. /*
  3.  * device.c --- SANA-II test device, device functions
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright (c) 1993 AmiTCP/IP Group,
  8.  *                    Helsinki University of Technology, Finland.
  9.  *                    All rights reserved.
  10.  *
  11.  * Created      : Thu Jan 21 17:32:55 1993 ppessi
  12.  * Last modified: Fri Feb 25 01:17:14 1994 ppessi
  13.  *
  14.  * $Log: device.c,v $
  15.  * Revision 4.1  1994/02/25  14:55:44  ppessi
  16.  * Fixed SAS C 6.51 features
  17.  *
  18.  * Revision 2.3  1993/10/20  15:17:52  jraja
  19.  * Added correct prototype for the CheckIO().
  20.  *
  21.  * Revision 2.2  1993/10/14  00:09:43  ppessi
  22.  * Changed RCS Id format
  23.  *
  24.  * Revision 2.1  93/05/14  16:48:21  ppessi
  25.  * Release version
  26.  * 
  27.  */
  28.  
  29. #include <string.h>
  30.  
  31. #include <dos/dostags.h>
  32. #include <dos/rdargs.h>
  33. #include <intuition/intuition.h>
  34. #include <rexx/storage.h>
  35. #include <rexx/rxslib.h>
  36.  
  37. #include <clib/alib_stdio_protos.h>
  38.  
  39. #ifdef __SASC
  40. #include <clib/exec_protos.h>
  41. #include <pragmas/exec_sysbase_pragmas.h>
  42. #include <clib/dos_protos.h>
  43. #include <pragmas/dos_pragmas.h>
  44. #include <clib/utility_protos.h>
  45. #include <pragmas/utility_pragmas.h>
  46. #include <clib/timer_protos.h>
  47. #include <pragmas/timer_pragmas.h>
  48. #endif
  49.  
  50. #ifdef __GNUC__
  51. #include <inline/exec.h>
  52. #include <inline/dos.h>
  53. #include <inline/utility.h>
  54. #include <inline/timer.h>
  55. #endif
  56.  
  57. #include "agnet.h"
  58. #include "agnet_protos.h"
  59. #include "agnet_rev.h"
  60. #include "bases.h"
  61.  
  62. /* Correct prototype for the CheckIO.
  63.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits) 
  64.  * instead of a pointer (32 bits)!)
  65.  */
  66. struct IORequest * CheckIO(struct IORequest *req);
  67.  
  68. /* Local prototypes */
  69. static ULONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2);
  70. static VOID CloseUnit(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  71. static VOID ExpungeUnit(struct AgnetDevUnit *adu);
  72. static VOID TermIO(struct IOSana2Req *ios2);
  73. static VOID GetSpecialStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  74. static VOID GetGlobalStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  75. static VOID GetTypeStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  76. static VOID TrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  77. static VOID UnTrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  78. static VOID PacketReceived(struct AgnetDevUnit *adu, ULONG length, ULONG type);
  79. static VOID PacketSent(struct AgnetDevUnit *adu, ULONG length, ULONG type);
  80. static VOID PacketOverrun(struct AgnetDevUnit *adu);
  81. static VOID ReceivedGarbage(struct AgnetDevUnit *adu);
  82. static VOID PacketDropped(struct AgnetDevUnit *adu, ULONG type);
  83. static VOID ReceivedOrphan(struct AgnetDevUnit *adu);
  84. static VOID ConfigInterface(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  85. static VOID GetStationAddress(struct AgnetDevUnit *, struct IOSana2Req *);
  86. static VOID DeviceQuery(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  87. static VOID Online(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  88. static VOID Offline(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  89. static VOID OnEvent(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  90. static VOID DoEvent(struct AgnetDevUnit *adu, ULONG event);
  91. static VOID WritePacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  92. static VOID ReadPacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  93. static VOID ReadOrphan(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  94. static VOID SendPacket(struct DelayRequest *delayed);
  95. static VOID ReceivePacket(struct DelayRequest *delayed);
  96. static VOID DoReceive(struct AgnetDevUnit *, struct DelayRequest *delayed );
  97. static VOID CopyBack(struct AgnetDevUnit *, struct IOSana2Req *, 
  98.              struct DelayRequest *);
  99.  
  100. /*
  101.  * Device Open vector
  102.  *
  103.  * a1 - SANA2 IO Request
  104.  * a6 - Pointer to our device base
  105.  * d0 - Unit number
  106.  * d1 - Flags
  107.  */
  108. ULONG ASM 
  109. DevOpen(REG(a1) struct IOSana2Req *ios2,
  110.     REG(d0) ULONG s2unit,
  111.     REG(d1) ULONG s2flags)
  112. {
  113.   struct AgnetDevice *AgnetDev = AgnetDeviceBase;
  114.   struct AgnetDevUnit *adu;
  115.   struct TagItem *bufftag;
  116.   struct Library *UtilityBase;
  117.   struct BufferManagement *bm;
  118.   BYTE status = IOERR_UNITBUSY;
  119.  
  120.   /* Make sure our open remains single-threaded.
  121.      We may Wait() when starting up. If somebody
  122.      decides to DoExpunge() before we get the
  123.      semaphore, system is probably blowing up anyways.
  124.      */
  125.   ObtainSemaphore(&AgnetDev->ad_Lock);
  126.  
  127.   /* So we won't expunge ourselves... */
  128.   AgnetDev->ad_Dev_OpenCnt++;
  129.  
  130.   if (s2unit < AD_MAXUNITS)       /* Legal Unit */
  131.     if (adu = InitUnit(s2unit))      /* Initialize the unit? */
  132.       if (UtilityBase = OpenLibrary("utility.library", 37L)) { /* For Tag functions */
  133.  
  134.     /* Allocate a structure to store the pointers to the callback routines. */
  135.     if (bm = AllocMem(sizeof(*bm), MEMF_CLEAR|MEMF_PUBLIC)) {
  136.       /* Note: I don't complain if I can't find pointers to the callback routines.
  137.          This is because there are some programs that may need to open me, but
  138.          will never use any device commands that require the callbacks. */
  139.       if (bufftag = FindTagItem(S2_CopyToBuff, (struct TagItem *)ios2->ios2_BufferManagement)) {
  140.         bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
  141.       }
  142.       if (bufftag = FindTagItem(S2_CopyFromBuff, (struct TagItem *)ios2->ios2_BufferManagement)) {
  143.         bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
  144.       }
  145.       AddTail((struct List *)&adu->adu_BuffMgmt, (struct Node *)bm);
  146.  
  147.       /* Everything went okay. */
  148.       status = 0;
  149.       AgnetDev->ad_Dev_OpenCnt++;
  150.       AgnetDev->ad_Dev_Flags &= ~LIBF_DELEXP;
  151.       adu->adu_Unit_OpenCnt++;
  152.  
  153.       /* Fix up the initial io request */
  154.       ios2->ios2_BufferManagement = (VOID *)bm;
  155.       ios2->ios2_Req.io_Error = 0;
  156.       ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  157.       ios2->ios2_Req.io_Unit = adu;
  158.       ios2->ios2_Req.io_Device = AgnetDev;
  159.     }
  160.     CloseLibrary(UtilityBase);
  161.       }
  162.  
  163.   /* See if something went wrong. */
  164.   if (status) {
  165.     ios2->ios2_Req.io_Error = status;
  166.     ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  167.     ios2->ios2_Req.io_Device = (struct Device *) -1;
  168.   }
  169.   AgnetDev->ad_Dev_OpenCnt--;
  170.   ReleaseSemaphore(&AgnetDev->ad_Lock);
  171.  
  172.   return status;
  173. }
  174.  
  175. /*
  176.  * Device Close vector.
  177.  *
  178.  * a1 - IOReq
  179.  * a6 - Device Pointer
  180.  */
  181. BPTR ASM 
  182. DevClose(REG(a1) struct IOSana2Req *ios2)
  183. {
  184.   struct AgnetDevice *AgnetDev = AgnetDeviceBase;
  185.   struct AgnetDevUnit *adu;
  186.   BPTR seglist = 0L;
  187.  
  188.   ObtainSemaphore(&AgnetDev->ad_Lock);
  189.  
  190.   adu = (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
  191.   CloseUnit(adu, ios2);
  192.  
  193.   /* Trash the io_Device and io_Unit fields so that any attempt to use this
  194.      request will die immediatly. */
  195.  
  196.   ios2->ios2_Req.io_Device = (struct Device *) -1;
  197.   ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  198.  
  199.   AgnetDev->ad_Dev_OpenCnt--;
  200.  
  201.   /* Check to see if we've been asked to expunge. */
  202.   if (AgnetDev->ad_Dev_OpenCnt == 0 && AgnetDev->ad_Dev_Flags & LIBF_DELEXP) {
  203.     Signal(AgnetDev->ad_Task, SIGBREAKF_CTRL_F);
  204.   }
  205.   ReleaseSemaphore(&AgnetDev->ad_Lock);
  206.  
  207.   return seglist;
  208. }
  209.  
  210. /*
  211.  * Device Expunge vector
  212.  *
  213.  * a6 - Device base
  214.  *
  215.  * Note: You may NEVER EVER Wait() in expunge. Period.
  216.  *     Don't even *think* about it.
  217.  */
  218. BPTR ASM 
  219. DevExpunge(VOID)
  220. {
  221.   struct AgnetDevice *AgnetDev = AgnetDeviceBase;
  222.  
  223.   AgnetDev->ad_Dev_Flags |= LIBF_DELEXP;
  224.   Signal(AgnetDev->ad_Task, SIGBREAKF_CTRL_F);
  225.  
  226.   /* We can not expunge  */
  227.   return (BPTR)0L;
  228. }
  229.  
  230. /*
  231.  * Device Reserved vector (returns 0L)
  232.  */
  233. ULONG ASM 
  234. DevReserved(VOID)
  235. {
  236.   return 0L;
  237. }
  238.  
  239. /*
  240.  * BeginIO --- dispatch incoming requests
  241.  *
  242.  * a1 - The IO request
  243.  * a6 - The device base
  244.  */
  245. #define SLIP_IMMEDIATES 0L    /* No QUICK IO */
  246.  
  247. VOID ASM 
  248. DevBeginIO(REG(a1) struct IOSana2Req *ios2)
  249. {
  250.   register struct AgnetDevice *ad;
  251.   ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  252.  
  253.   if (ios2->ios2_Req.io_Command < S2_END) {
  254.     if ((ios2->ios2_Req.io_Flags & IOF_QUICK) &&
  255.     ((1L << ios2->ios2_Req.io_Command) & SLIP_IMMEDIATES)) {
  256.       PerformIO(ios2);
  257.     } else {
  258.       ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  259.       /* Send this to DEVICE Message Port */
  260.       ad = (struct AgnetDevice*)ios2->ios2_Req.io_Device;
  261.       PutMsg(&ad->ad_MsgPort, (struct Message *)ios2);
  262.     }
  263.   } else {
  264.     ios2->ios2_Req.io_Error = IOERR_NOCMD;
  265.     TermIO(ios2);
  266.   }
  267. }
  268.  
  269. /*
  270.  * The device AbortIO() entry point.
  271.  * 
  272.  * A1 - The IO request to be aborted.
  273.  * A6 - The device base.
  274.  */
  275. ULONG ASM 
  276. DevAbortIO(REG(a1) struct IOSana2Req *ios2)
  277. {
  278.   register struct AgnetDevUnit *adu = 
  279.     (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
  280.   register ULONG result = 0L;
  281.  
  282.   
  283.   LockUnit(adu);
  284.   if (ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG) {
  285.     switch(ios2->ios2_Req.io_Command) {
  286.     case CMD_READ:    result = AbortReq(&adu->adu_Rx,ios2);
  287.       break;
  288.  
  289.     case CMD_WRITE:     result = AbortReq(&adu->adu_Tx,ios2);
  290.       break;
  291.  
  292.     case S2_READORPHAN:    result = AbortReq(&adu->adu_RxOrph,ios2);
  293.       break;
  294.  
  295.     case S2_ONEVENT:    result = AbortReq(&adu->adu_Events,ios2);
  296.       break;
  297.  
  298.     default:        result = IOERR_NOCMD;
  299.       break;
  300.     }
  301.   }
  302.   UnlockUnit(adu);
  303.   return result;
  304. }
  305.  
  306. /*
  307.  * This funcion is used to locate an IO request in a linked
  308.  * list and abort it if found.
  309.  */
  310. static ULONG 
  311. AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
  312. {
  313.   struct Node *node, *next;
  314.   ULONG result = IOERR_NOCMD;
  315.  
  316.   node = (struct Node *)minlist->mlh_Head;
  317.  
  318.   while (!TAILP(node)) {
  319.     next = node->ln_Succ;
  320.  
  321.     if (node == (struct Node *)ios2) {
  322.       Remove((struct Node *)ios2);
  323.       ios2->ios2_Req.io_Error = IOERR_ABORTED;
  324.       TermIO(ios2);
  325.       result = 0;
  326.     }
  327.     node = next;
  328.   }
  329.   return result;
  330. }
  331.  
  332. /*
  333.  * Real expunge
  334.  */
  335. BOOL 
  336. DoExpunge(struct AgnetDevice *adb)
  337. {
  338.   ULONG i;
  339.  
  340.   /* Well, if there is somebody trying to open,
  341.      they stuck with this */
  342.   ObtainSemaphore(&adb->ad_Lock);
  343.   if (adb->ad_Device.lib_OpenCnt != 0) {
  344.     ReleaseSemaphore(&adb->ad_Lock);
  345.     return FALSE;
  346.   }
  347.   Forbid();
  348.   Remove((struct Node *)adb);
  349.   Permit();
  350.  
  351.   /* Free up Units */
  352.   for (i=0; i < AD_MAXUNITS; i++) {
  353.     if (adb->ad_Units[i])
  354.       ExpungeUnit((struct AgnetDevUnit *)adb->ad_Units[i]);
  355.     adb->ad_Units[i] = NULL;
  356.   }
  357.  
  358.   return TRUE;
  359. }
  360.  
  361. /*
  362.  * InitUnit
  363.  *
  364.  * Initialize (if needed) a new agnet.device Unit
  365.  */
  366. struct AgnetDevUnit *
  367. InitUnit(ULONG s2unit)
  368. {
  369.   struct AgnetDevUnit *adu;
  370.   struct AgnetDevice *adb = AgnetDeviceBase;
  371.  
  372.   /* Check to see if the Unit is already up and running.  If
  373.      it is, just drop through.  If not, try to start it up. */
  374.   if (adu = (struct AgnetDevUnit *)adb->ad_Units[s2unit])
  375.     return adu;
  376.  
  377.   /* Allocate a new Unit structure */
  378.   adu = AllocMem(sizeof(*adu), MEMF_CLEAR|MEMF_PUBLIC);
  379.   if (!adu)
  380.     return NULL;
  381.  
  382.   /* Do some initialization on the Unit structure */
  383. #if 0
  384.   NewList(&adu->adu_Unit_MsgPort.mp_MsgList);
  385.   adu->adu_Unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
  386.   adu->adu_Unit_MsgPort.mp_Flags = PA_IGNORE;
  387.   adu->adu_Unit_MsgPort.mp_Node.ln_Name = AGNETDEVNAME;
  388. #endif
  389.   adu->adu_UnitNum = s2unit;
  390.   adu->adu_Device = (struct Device *) adb;
  391.  
  392.   /* Try to read in our configuration file */
  393.   if (!ReadConfig(adu)) {
  394.     FreeMem(adu, sizeof(*adu));
  395.     return NULL;
  396.   }
  397.  
  398.   /* Initialize our list semaphore */
  399.   InitSemaphore(&adu->adu_Lock);
  400.  
  401.   /* Initialize our linked lists. */
  402.   NewList((struct List *)&adu->adu_FreeToTx);
  403.   NewList((struct List *)&adu->adu_Rx);
  404.   NewList((struct List *)&adu->adu_RxOrph);
  405.   NewList((struct List *)&adu->adu_Tx);
  406.   NewList((struct List *)&adu->adu_Events);
  407.   NewList((struct List *)&adu->adu_Track);
  408.   NewList((struct List *)&adu->adu_BuffMgmt);
  409.  
  410.   /* Allocate memory buffers */
  411.   DoOnline(adu);
  412.  
  413.   /* Set up the Unit structure pointer in the device base */
  414.   adb->ad_Units[s2unit] = adu;
  415.  
  416.   return adu;
  417. }
  418.  
  419. /*
  420.  * CloseUnit
  421.  *
  422.  * This function closes unit and frees resources
  423.  * allocated for each opener.
  424.  */
  425. static VOID 
  426. CloseUnit(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  427. {
  428.   register struct BufferManagement *bm = ios2->ios2_BufferManagement;
  429.  
  430.   LockUnit(adu);
  431.  
  432.   if (bm) {
  433.     ios2->ios2_BufferManagement = NULL;
  434.     Remove((struct Node *)bm);
  435.     FreeMem(bm, sizeof(*bm));
  436.   }
  437.   adu->adu_Unit.unit_OpenCnt--;
  438.  
  439.   UnlockUnit(adu);
  440. }
  441.  
  442. /*
  443.  *  ExpungeUnit
  444.  *
  445.  *  This function is called from the DoExpunge routine.
  446.  *  The unit structure and all subsequent allocations are freed.
  447.  */
  448. static VOID 
  449. ExpungeUnit(struct AgnetDevUnit *adu)
  450. {
  451.   struct IOSana2Req *ios2;
  452.   struct SuperS2PTStats *sstats;
  453.   int i;
  454.   struct List *io_queues[5];
  455.  
  456.   /* Eliminate every queues */
  457.   LockUnit(adu);
  458.  
  459.   io_queues[0] = (struct List *)&adu->adu_Rx;
  460.   io_queues[1] = (struct List *)&adu->adu_Tx;
  461.   io_queues[2] = (struct List *)&adu->adu_RxOrph;
  462.   io_queues[3] = (struct List *)&adu->adu_Events;
  463.   io_queues[4] = NULL;
  464.  
  465.   for (i = 0; io_queues[i]; i++) {
  466.     while(ios2 = (struct IOSana2Req *)RemHead(io_queues[i])) {
  467.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  468.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  469.       TermIO(ios2);
  470.      }
  471.   }
  472.  
  473.   /* Tracking data was allocated by us */
  474.   while(sstats = (struct SuperS2PTStats*)
  475.     RemHead((struct List *)&adu->adu_Track)) {
  476.     FreeMem(sstats, sizeof(*sstats));
  477.   }
  478.  
  479.   DoOffline(adu);
  480.  
  481.   UnlockUnit(adu);
  482.  
  483.   FreeMem(adu, sizeof(*adu));
  484. }
  485.  
  486. /*
  487.  * This routine is used to dispatch an IO request either from BeginIO
  488.  * or from the Unit process.
  489.  */
  490. VOID 
  491. PerformIO(struct IOSana2Req *ios2)
  492. {
  493.   struct AgnetDevUnit *adu = (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
  494.  
  495.   if (ios2->ios2_Req.io_Device == 
  496.       AgnetDeviceBase->ad_Timer.tr_node.io_Device) {
  497.     ReceivePacket(ios2);
  498.     return;
  499.   }
  500.  
  501.   ios2->ios2_Req.io_Error = 0;
  502.  
  503.   switch(ios2->ios2_Req.io_Command) {
  504.   case CMD_READ:              ReadPacket(adu,ios2);
  505.     break;
  506.  
  507.   case CMD_WRITE:             WritePacket(adu,ios2);
  508.     break;
  509.  
  510.   case S2_DEVICEQUERY:        DeviceQuery(adu,ios2);
  511.     break;
  512.  
  513.   case S2_GETSTATIONADDRESS:  GetStationAddress(adu,ios2);
  514.     break;
  515.  
  516.   case S2_CONFIGINTERFACE:    ConfigInterface(adu,ios2);
  517.     break;
  518. #if 0
  519.     /* Non-existing commands */
  520.   case S2_ADDSTATIONALIAS:
  521.   case S2_DELSTATIONALIAS:
  522. #endif
  523.   case S2_ADDMULTICASTADDRESS:
  524.   case S2_DELMULTICASTADDRESS:
  525.   case S2_MULTICAST:
  526.     ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  527.     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  528.     TermIO(ios2);
  529.     break;
  530.  
  531.   case S2_BROADCAST:        WritePacket(adu,ios2);
  532.     break;
  533.  
  534.   case S2_TRACKTYPE:        TrackType(adu,ios2);
  535.     break;
  536.  
  537.   case S2_UNTRACKTYPE:      UnTrackType(adu,ios2);
  538.     break;
  539.  
  540.   case S2_GETTYPESTATS:     GetTypeStats(adu,ios2);
  541.     break;
  542.  
  543.   case S2_GETSPECIALSTATS:  GetSpecialStats(adu,ios2);
  544.     break;
  545.  
  546.   case S2_GETGLOBALSTATS:   GetGlobalStats(adu,ios2);
  547.     break;
  548.  
  549.   case S2_ONEVENT:          OnEvent(adu,ios2);
  550.     break;
  551.  
  552.   case S2_READORPHAN:       ReadOrphan(adu,ios2);
  553.     break;
  554.  
  555.   case S2_ONLINE:           Online(adu,ios2);
  556.     break;
  557.  
  558.   case S2_OFFLINE:          Offline(adu,ios2);
  559.     break;
  560.  
  561.   default:
  562.     ios2->ios2_Req.io_Error = IOERR_NOCMD;
  563.     TermIO(ios2);
  564.     break;
  565.   }
  566. }
  567.  
  568. /*
  569.  * This function is used to return an IO request
  570.  * back to the sender.
  571.  */
  572. static VOID 
  573. TermIO(struct IOSana2Req *ios2)
  574. {
  575.   if (!(ios2->ios2_Req.io_Flags & IOF_QUICK))
  576.     ReplyMsg((struct Message *)ios2);
  577. }
  578.  
  579. /*
  580.  * This function returns any device specific statistics that
  581.  * we may have.
  582.  *
  583.  * Currently, there is none.
  584.  *
  585.  * Ethernet may require some
  586.  */
  587. static VOID 
  588. GetSpecialStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  589. {
  590.   struct Sana2SpecialStatHeader *stats;
  591.  
  592.   stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
  593.  
  594.   stats->RecordCountSupplied = 0;
  595.   TermIO(ios2);
  596. }
  597.  
  598. /*
  599.  * This function returns the global statistics for the
  600.  * slip device.
  601.  */
  602. static VOID 
  603. GetGlobalStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  604. {
  605.   struct Sana2DeviceStats *stats;
  606.  
  607.   if (stats = (struct Sana2DeviceStats *)ios2->ios2_StatData) {
  608.     stats->PacketsReceived    = adu->adu_Stats.PacketsReceived;
  609.     stats->PacketsSent        = adu->adu_Stats.PacketsSent;
  610.     stats->BadData        = adu->adu_Stats.BadData;
  611.     stats->Overruns        = adu->adu_Stats.Overruns;
  612.     stats->UnknownTypesReceived = adu->adu_Stats.UnknownTypesReceived;
  613.     stats->Reconfigurations    = adu->adu_Stats.Reconfigurations;
  614.     stats->LastStart.tv_secs    = adu->adu_Stats.LastStart.tv_secs;
  615.     stats->LastStart.tv_micro    = adu->adu_Stats.LastStart.tv_secs;
  616.   } else {
  617.     ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  618.     ios2->ios2_WireError = S2WERR_NULL_POINTER;
  619.   }
  620.   TermIO(ios2);
  621. }
  622.  
  623. /*
  624.  * This function returns statistics for a specific
  625.  * type of packet that is being tracked.
  626.  *
  627.  * Just to be thourough, I have arbitrarily picked
  628.  * the packet type for SLIP IP packets to be 2048, the
  629.  * same as that used for Ethernet.  This will at least
  630.  * allow you to track IP packets.
  631.  */
  632. static VOID
  633. GetTypeStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  634. {
  635.   struct Sana2PacketTypeStats *stats;
  636.   struct SuperS2PTStats *sstats;
  637.  
  638.   if (stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData) {
  639.     LockUnit(adu);
  640.  
  641.     sstats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  642.  
  643.     /* Find asked packet type from tracking list */
  644.     while (sstats->ss_Node.mln_Succ) {
  645.       if (ios2->ios2_PacketType == sstats->ss_PType) {
  646.     stats->PacketsSent     = sstats->ss_Stats.PacketsSent;
  647.     stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
  648.     stats->BytesSent       = sstats->ss_Stats.BytesSent;
  649.     stats->BytesReceived   = sstats->ss_Stats.BytesReceived;
  650.     stats->PacketsDropped  = sstats->ss_Stats.PacketsDropped;
  651.     break;
  652.       }
  653.       sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
  654.     }
  655.     UnlockUnit(adu);
  656.     if (!sstats->ss_Node.mln_Succ) {
  657.       ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  658.       ios2->ios2_WireError    = S2WERR_NOT_TRACKED;
  659.     }
  660.   } else {
  661.     ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  662.     ios2->ios2_WireError = S2WERR_NULL_POINTER;
  663.   }
  664.   TermIO(ios2);
  665. }
  666.  
  667. /*
  668.  * This function adds a packet type to the list
  669.  * of those that are being tracked.
  670.  */
  671. static VOID 
  672. TrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  673. {
  674.   struct SuperS2PTStats *stats;
  675.   ULONG type = ios2->ios2_PacketType;
  676.  
  677.   LockUnit(adu);
  678.  
  679.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  680.  
  681.   while (stats->ss_Node.mln_Succ) {
  682.     if (type == stats->ss_PType) {
  683.       ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  684.       ios2->ios2_WireError    = S2WERR_ALREADY_TRACKED;
  685.     }
  686.     stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  687.   }
  688.   if (!stats->ss_Node.mln_Succ) {
  689.     if(stats = AllocMem(sizeof(*stats), MEMF_CLEAR|MEMF_PUBLIC)) {
  690.       stats->ss_PType = type;
  691.       AddTail((struct List *)&adu->adu_Track, (struct Node *)stats);
  692.     }
  693.   }
  694.   UnlockUnit(adu);
  695.  
  696.   TermIO(ios2);
  697. }
  698.  
  699. /*
  700.  * This function removes a packet type from the
  701.  * list of those that are being tracked.
  702.  */
  703. static VOID 
  704. UnTrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  705. {
  706.   struct SuperS2PTStats *stats;
  707.  
  708.   LockUnit(adu);
  709.  
  710.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  711.  
  712.   while (stats->ss_Node.mln_Succ) {
  713.     if (ios2->ios2_PacketType == stats->ss_PType) {
  714.       Remove((struct Node *)stats);
  715.       FreeMem(stats, sizeof(*stats));
  716.       stats = NULL;
  717.       break;
  718.     }
  719.     stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  720.   }
  721.   if(stats) {
  722.     ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  723.     ios2->ios2_WireError    = S2WERR_NOT_TRACKED;
  724.   }
  725.   UnlockUnit(adu);
  726.  
  727.   TermIO(ios2);
  728. }
  729.  
  730. /*
  731.  * This function is called whenever a packet is received
  732.  */
  733. static VOID 
  734. PacketReceived(struct AgnetDevUnit *adu, ULONG length, ULONG type)
  735. {
  736.   struct SuperS2PTStats *stats;
  737.  
  738.   adu->adu_Stats.PacketsReceived++;
  739.  
  740.   LockUnit(adu);
  741.  
  742.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  743.  
  744.   while (stats->ss_Node.mln_Succ) {
  745.     if (stats -> ss_PType == type) {
  746.       stats -> ss_Stats.PacketsReceived++;
  747.       stats -> ss_Stats.BytesReceived += length;
  748.       break;
  749.     }
  750.     stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
  751.   }
  752.  
  753.   UnlockUnit(adu);
  754. }
  755.  
  756. /*
  757.  * This function is called whenever a packet is sent
  758.  */
  759. static VOID 
  760. PacketSent(struct AgnetDevUnit *adu, ULONG length, ULONG type)
  761. {
  762.   struct SuperS2PTStats *stats;
  763.  
  764.   adu->adu_Stats.PacketsSent++;
  765.  
  766.   LockUnit(adu);
  767.  
  768.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  769.  
  770.   while (stats->ss_Node.mln_Succ) {
  771.     if (stats -> ss_PType == type) {
  772.       stats -> ss_Stats.PacketsSent++;
  773.       stats -> ss_Stats.BytesSent += length;
  774.       break;
  775.     }
  776.     stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
  777.   }
  778.  
  779.   UnlockUnit(adu);
  780. }
  781.  
  782. /*
  783.  * This function is called a packet overruns
  784.  */
  785. static VOID 
  786. PacketOverrun(struct AgnetDevUnit *adu)
  787. {
  788.   adu->adu_Stats.Overruns++;
  789.   DoEvent(adu, S2EVENT_HARDWARE | S2EVENT_RX | S2EVENT_ERROR);
  790. }
  791.  
  792. /*
  793.  * This function is called whenever a packet with
  794.  * garbage data is encountered.
  795.  */
  796. static VOID 
  797. ReceivedGarbage(struct AgnetDevUnit *adu)
  798. {
  799.   adu->adu_Stats.BadData++;
  800.   DoEvent(adu, S2EVENT_HARDWARE | S2EVENT_RX | S2EVENT_ERROR);
  801. }
  802.  
  803. /*
  804.  * This function is called whenever a packet
  805.  * is dropped by the SLIP driver.
  806.  */
  807. static VOID 
  808. PacketDropped(struct AgnetDevUnit *adu, ULONG type)
  809. {
  810.   struct SuperS2PTStats *stats;
  811.  
  812.   LockUnit(adu);
  813.  
  814.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  815.  
  816.   while (stats->ss_Node.mln_Succ) {
  817.     if (stats -> ss_PType == type) {
  818.       stats -> ss_Stats.PacketsDropped++;
  819.       break;
  820.     }
  821.     stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
  822.   }
  823.  
  824.   UnlockUnit(adu);
  825. }
  826.  
  827. /*
  828.  * This function is called whenever an orphan packet
  829.  * is received
  830.  */
  831. static VOID 
  832. ReceivedOrphan(struct AgnetDevUnit *adu)
  833. {
  834.   adu->adu_Stats.UnknownTypesReceived++;
  835. }
  836.  
  837. /*
  838.  * This function handles S2_CONFIGINTERFACE commands.
  839.  */
  840. static VOID 
  841. ConfigInterface(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  842. {
  843.   /* Note: we may only be configured once. */
  844.   if (!(adu->adu_State & AGUF_CONFIG)) {
  845.     switch (adu->adu_HardwareType) {
  846.     case S2WireType_PPP:
  847.     case S2WireType_SLIP:
  848.     case S2WireType_CSLIP:
  849.     case S2WireType_Ethernet:
  850.     case S2WireType_IEEE802:
  851.     case S2WireType_Arcnet:
  852.     case S2WireType_LocalTalk:
  853.     case S2WireType_AmokNet:
  854.       /* Copy given address as our Station Address */
  855.       memcpy(&adu->adu_Addr, &ios2->ios2_SrcAddr, MAX_ADDR_BYTES);
  856.       /*FALLTHROUGH*/
  857.     default:
  858.       adu->adu_State |= AGUF_CONFIG;
  859.     }
  860.   } else {
  861.     /* Sorry, we're already configured. */
  862.     ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  863.     ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  864.   }
  865.   TermIO(ios2);
  866. }
  867.  
  868. /*
  869.  * This function handles S2_GETSTATIONADDRESS commands.
  870.  */
  871. static VOID 
  872. GetStationAddress(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  873. {
  874.   memcpy(ios2->ios2_DstAddr, adu->adu_Addr, MAX_ADDR_BYTES);
  875.   if (adu->adu_State & AGUF_CONFIG)
  876.     memcpy(ios2->ios2_SrcAddr, adu->adu_Addr, MAX_ADDR_BYTES);
  877.   else 
  878.     memset(ios2->ios2_SrcAddr, 0xff, MAX_ADDR_BYTES);
  879.   TermIO(ios2);
  880. }
  881.  
  882. /*
  883.  * This function handles S2_DEVICEQUERY comands.
  884.  */
  885. static VOID 
  886. DeviceQuery(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  887. {
  888.   struct Sana2DeviceQuery *sdq;
  889.  
  890.   sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
  891.  
  892.   sdq->DeviceLevel   = 0L;
  893.   sdq->AddrFieldSize = adu->adu_AddrFieldSize;
  894.   sdq->MTU           = adu->adu_MaxTU;
  895.   sdq->BPS           = adu->adu_BPS;
  896.   sdq->HardwareType  = adu->adu_HardwareType;
  897.  
  898.   sdq->SizeSupplied = sizeof(*sdq);
  899.   TermIO(ios2);
  900. }
  901.  
  902. /*
  903.  * This routime handles CMD_ONLINE commands.
  904.  */
  905. static VOID 
  906. Online(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  907. {
  908.   if (!(adu->adu_State & AGUF_ONLINE)) {
  909.     /* We're offline. Go online. */
  910.     LockUnit(adu);
  911.     if (DoOnline(adu)) {
  912.       /* Couldn't get online */
  913.       ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  914.       ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  915.     } 
  916.     UnlockUnit(adu);
  917.   }
  918.   TermIO(ios2);
  919. }
  920.  
  921. /* 
  922.  * Actual Online, return 0 on success
  923.  *
  924.  * Caller should have a lock on the unit
  925.  */
  926. LONG
  927. DoOnline(struct AgnetDevUnit *adu)
  928. {
  929.   struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
  930.   ULONG mtu; LONG i; BOOL error = TRUE;
  931.   struct DelayRequest *txed;
  932.  
  933.   /* Allocate transfer buffer */
  934.   mtu = adu->adu_MaxTU + 64;
  935.   for (i = 0; i < MAX_TXED; i++) {
  936.     if (adu->adu_TxEd[i]) {
  937.       error = FALSE;
  938.       continue;
  939.     }
  940.     if (!(txed = CreateIORequest(&adb->ad_MsgPort, 
  941.                  sizeof(struct DelayRequest) + mtu))) 
  942.       break;
  943.     error = FALSE;
  944.     adu->adu_TxEd[i] = txed;
  945.     txed->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  946.     txed->tr_node.io_Device = adb->ad_Timer.tr_node.io_Device;
  947.     txed->tr_node.io_Unit = adb->ad_Timer.tr_node.io_Unit;
  948.     txed->tr_node.io_Command = TR_ADDREQUEST;
  949.     txed->dr_Unit = adu;
  950.     txed->dr_Len = mtu;
  951.     AddHead(&adu->adu_FreeToTx, txed);
  952.   }
  953.  
  954.   if (!error) {
  955.     adu->adu_State |= AGUF_ONLINE;
  956.     GetSysTime(&adu->adu_Stats.LastStart);
  957.     /* In case someone wants to know...*/
  958.     DoEvent(adu, S2EVENT_ONLINE);
  959.   }
  960.   return error;
  961. }
  962.  
  963. /*
  964.  * This routine handles CMD_OFFLINE commands.
  965.  * Any pending read or write request will be sent to 
  966.  * their owners
  967.  */
  968. static VOID 
  969. Offline(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  970. {
  971.   struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
  972.  
  973.   if (adu->adu_State & AGUF_ONLINE) {
  974.     /* We're online, so shut everything down. */
  975.     LockUnit(adu);
  976.     DoOffline(adu);
  977.     UnlockUnit(adu);
  978.   }
  979.  
  980.   TermIO(ios2);
  981. }
  982.  
  983. /*
  984.  * Put the unit offline 
  985.  *
  986.  * Caller should have a lock on the unit
  987.  */
  988. VOID
  989. DoOffline(struct AgnetDevUnit *adu)
  990. {
  991.   struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
  992.   struct IOSana2Req *ios2;
  993.   int i;
  994.   struct DelayRequest *txed;
  995.  
  996.   adu->adu_State &= ~AGUF_ONLINE;
  997.  
  998.   while(ios2 = (struct IOSana2Req *)
  999.     RemHead((struct List *)&adu->adu_Rx)) {
  1000.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1001.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1002.     TermIO(ios2);
  1003.   }
  1004.  
  1005.   while(ios2 = (struct IOSana2Req *)
  1006.     RemHead((struct List *)&adu->adu_RxOrph)) {
  1007.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1008.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1009.     TermIO(ios2);
  1010.   }
  1011.  
  1012.   while(ios2 = (struct IOSana2Req *)
  1013.     RemHead((struct List *)&adu->adu_Tx)) {
  1014.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1015.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1016.     TermIO(ios2);
  1017.   }
  1018.  
  1019.   /* 
  1020.    * Abort still pending delayrequests, 
  1021.    * free all delayrequests
  1022.    */
  1023.   for (i = MAX_TXED - 1; i >= 0; i--) {
  1024.     if (txed = adu->adu_TxEd[i]) {
  1025.       if (!CheckIO(txed))
  1026.     AbortIO(txed);
  1027.       WaitIO(txed);        /* also removes from free queue */
  1028.       DeleteIORequest(txed);
  1029.     }
  1030.     adu->adu_TxEd[i] = NULL;
  1031.   }
  1032.   
  1033.   DoEvent(adu, S2EVENT_OFFLINE);
  1034. }
  1035. /* 
  1036.  * This routine handles S2_ONEVENT commands 
  1037.  */
  1038. static VOID 
  1039. OnEvent(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1040. {
  1041.   /* Two special cases.
  1042.    *  If we are (on/off)line, and ask (on/off)line event,
  1043.    *  we return immediately 
  1044.    */
  1045.   if (ios2->ios2_WireError == S2EVENT_ONLINE &&
  1046.       adu->adu_State & AGUF_ONLINE ||
  1047.       ios2->ios2_WireError == S2EVENT_OFFLINE &&
  1048.       !(adu->adu_State & AGUF_ONLINE)) {
  1049.     TermIO(ios2);
  1050.   } else {
  1051.     LockUnit(adu);
  1052.     AddTail((struct List *)&adu->adu_Events, (struct Node *)ios2);
  1053.     UnlockUnit(adu);
  1054.   }
  1055. }
  1056.  
  1057. /*
  1058.  * This routine is called whenever an "important"
  1059.  * SANA-II event occurs.
  1060.  */
  1061. static VOID 
  1062. DoEvent(struct AgnetDevUnit *adu, ULONG event)
  1063. {
  1064.   struct IOSana2Req *ios2;
  1065.   struct IOSana2Req *ios2_next;
  1066.  
  1067.   LockUnit(adu);
  1068.  
  1069.   ios2 = (struct IOSana2Req *)adu->adu_Events.mlh_Head;
  1070.  
  1071.   while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ) {
  1072.     ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
  1073.  
  1074.     /* Is this the event they are looking for? */
  1075.     if(ios2->ios2_WireError & event) {
  1076.       Remove((struct Node *)ios2);
  1077.       ios2->ios2_WireError = event;
  1078.       TermIO(ios2);
  1079.     }
  1080.     ios2 = ios2_next;
  1081.   }
  1082.  
  1083.   UnlockUnit(adu);
  1084. }
  1085.  
  1086. /*
  1087.  * This function is used for handling CMD_WRITE and S2_BROADCAST
  1088.  * commands.
  1089.  */
  1090. static VOID 
  1091. WritePacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1092. {
  1093.   /* Make sure that we are online. */
  1094.   if (!(adu->adu_State & AGUF_ONLINE)) {
  1095.     /* Sorry, we're offline */
  1096.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1097.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1098.     TermIO(ios2);
  1099.     return;
  1100.   }
  1101.  
  1102.   /* Is the data length legal? */
  1103.   if (ios2->ios2_DataLength < adu->adu_MinTU ||
  1104.       ios2->ios2_DataLength > adu->adu_MaxTU) {
  1105.     /* Sorry, the packet is too long or too small! */
  1106.     ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
  1107.     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  1108.     TermIO(ios2);
  1109.     DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_TX | S2EVENT_ERROR);
  1110.     return;
  1111.   }
  1112.  
  1113.   /* We call the SendPacket if no delay */
  1114.   ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  1115.  
  1116.   {
  1117.     struct DelayRequest *delayed;
  1118.     LockUnit(adu);
  1119.     AddTail((struct List *)&adu->adu_Tx,(struct Node *)ios2);
  1120.     /* 
  1121.      * If there is free delay requests, 
  1122.      * try to send immediately
  1123.      */
  1124.     delayed = (struct DelayRequest *)
  1125.       RemHead((struct List *)&adu->adu_FreeToTx);
  1126.     UnlockUnit(adu);
  1127.  
  1128.     if (delayed)
  1129.       SendPacket(delayed);
  1130.   }
  1131.   return;
  1132. }
  1133.  
  1134. /*
  1135.  * This routine handles CMD_READ commands.  We
  1136.  * always queue these unless we're offline.
  1137.  */
  1138. static VOID 
  1139. ReadPacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1140. {
  1141.   if(adu->adu_State & AGUF_ONLINE) {
  1142.     /* Queue it... */
  1143.     LockUnit(adu);
  1144.     AddTail((struct List *)&adu->adu_Rx, (struct Node *)ios2);
  1145.     UnlockUnit(adu);
  1146.     return;
  1147.   }
  1148.  
  1149.   /* Sorry, we're offline */
  1150.   ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1151.   ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1152.   TermIO(ios2);
  1153. }
  1154.  
  1155. /*
  1156.  * This routine handles CMD_READORPHAN commands.  We
  1157.  * always queue these unless we're offline.
  1158.  */
  1159. static VOID
  1160. ReadOrphan(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1161. {
  1162.   if(adu->adu_State & AGUF_ONLINE) {
  1163.     /* Queue it... */
  1164.     LockUnit(adu);
  1165.     AddTail((struct List *)&adu->adu_RxOrph, (struct Node *)ios2);
  1166.     UnlockUnit(adu);
  1167.     return;
  1168.   }
  1169.  
  1170.   /* Sorry, we're offline */
  1171.   ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1172.   ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1173.   TermIO(ios2);
  1174. }
  1175.  
  1176. /*
  1177.  * "Send" next queued packet 
  1178.  */
  1179. static VOID
  1180. SendPacket(struct DelayRequest *delayed)
  1181. {
  1182.   struct AgnetDevUnit *adu = delayed->dr_Unit;
  1183.   struct BufferManagement *bm;
  1184.   struct IOSana2Req *ios2 = NULL;
  1185.   LONG length; ULONG delay;
  1186.  
  1187.   LockUnit(adu);
  1188.  
  1189.   while (!ios2) {
  1190.     ios2 = (struct IOSana2Req *)RemHead((struct List *)&adu->adu_Tx);
  1191.     /* There is nothing to send */
  1192.     if (!ios2) {
  1193.       AddHead((struct List *)&adu->adu_FreeToTx,(struct Node *)delayed);
  1194.       UnlockUnit(adu);
  1195.       return;
  1196.     }
  1197.  
  1198.     length = ios2->ios2_DataLength;
  1199.  
  1200.     /* Update statistics */
  1201.     PacketSent(adu, length, ios2->ios2_PacketType);
  1202.  
  1203.     /* Should we lose the packet? */
  1204.     if (adu->adu_Loss && adu->adu_Loss > LRandom() % LOSS_MAX) {
  1205.       TermIO(ios2);
  1206.       ios2 = NULL;
  1207.     }
  1208.   }
  1209.   UnlockUnit(adu);
  1210.  
  1211.   if (length > delayed->dr_Len)
  1212.     length = delayed->dr_Len;
  1213.  
  1214.   bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
  1215.  
  1216.   /* Copy the data out of the packet into timer request buffer. */
  1217.   if (bm->bm_CopyFromBuffer &&          
  1218.       (*bm->bm_CopyFromBuffer)    /* we should have this tag, really */
  1219.       (delayed->dr_Data, ios2->ios2_Data, length)) {
  1220.     delayed->dr_DataLen = length;
  1221.     /* Copy addresses */
  1222.     if ((delayed->dr_PPUnit = adu->adu_PPUnit) < 0) {
  1223.       WORD adrlen = adu->adu_AddrFieldSize + 7 >> 3;
  1224.       memcpy(delayed->dr_DstAddr, ios2->ios2_DstAddr, adrlen);
  1225.       memcpy(delayed->dr_SrcAddr, adu->adu_Addr, adrlen);
  1226.     }
  1227.     /* Set hwtype */
  1228.     delayed->dr_HardwareType = adu->adu_HardwareType;
  1229.     delayed->dr_PacketType = ios2->ios2_PacketType;
  1230.     /* We should recognize broadcasts or multicasts */
  1231.     delayed->dr_Cmd = ios2->ios2_Req.io_Command;
  1232.     /*  Make errors */
  1233.     if (adu->adu_Errors) {
  1234.       LONG total = adu->adu_Errors * length * 8 / (LRandom() % ERRORS_MAX);
  1235.       while (total-- > 0) {
  1236.       /* Make a bit error.. */
  1237.     ULONG position = LRandom() & 0x7fffffffL;
  1238.     /* flip a bit */
  1239.     delayed->dr_Data[(position / 8) % length] ^= 1 << (position % 8);
  1240.       }
  1241.     }
  1242.  
  1243.     /* calculate delay */
  1244.     delay = adu->adu_Delay;
  1245.     if (delay && adu->adu_Deviation) 
  1246.       delay = RandomDev(delay, adu->adu_Deviation);
  1247.  
  1248.     if (delay) {
  1249.       delayed->tr_node.io_Command = TR_ADDREQUEST;
  1250.       delayed->tr_time.tv_secs = delay / 1000;
  1251.       delayed->tr_time.tv_micro = (delay % 1000) * 1000;
  1252.       SendIO(delayed);
  1253.     } else {
  1254.       /* Fallthrough */
  1255.       ReceivePacket(delayed);
  1256.     }
  1257.   } else {
  1258.     /* Something went wrong...*/
  1259.     ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  1260.     ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  1261.     DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_TX | S2EVENT_BUFF | S2EVENT_ERROR);
  1262.   }
  1263.  
  1264.   TermIO(ios2);
  1265. }
  1266.  
  1267. /*
  1268.  * This routine is called whenever a packet is received.
  1269.  * It return all appropriate read requests
  1270.  */
  1271. static VOID
  1272. ReceivePacket(struct DelayRequest *delayed)
  1273. {
  1274.   struct AgnetDevUnit *adu;
  1275.   int i; 
  1276.  
  1277.   if (delayed->dr_PPUnit >= 0 && delayed->dr_PPUnit < AD_MAXUNITS) {
  1278.     adu = (struct AgnetDevUnit *)AgnetDeviceBase->ad_Units[delayed->dr_PPUnit];
  1279.     if (adu)
  1280.       DoReceive(adu, delayed);
  1281.   } else {
  1282.     for (i = 0; i < AD_MAXUNITS; i++) {
  1283.       if (!(adu = (struct AgnetDevUnit *)AgnetDeviceBase->ad_Units[i]))
  1284.     continue;            /* No unit */
  1285.       if (delayed->dr_HardwareType != adu->adu_HardwareType) 
  1286.     continue;            /* Different hardware */
  1287.       if (delayed->dr_Cmd != S2_BROADCAST &&
  1288.       memcmp(delayed->dr_DstAddr, adu->adu_Addr, 
  1289.          adu->adu_AddrFieldSize + 7 >> 3)) 
  1290.     continue;            /* Address mismatched */
  1291.       DoReceive(adu, delayed);
  1292.     }
  1293.   } 
  1294.  
  1295.   SendPacket(delayed);
  1296. }
  1297.  
  1298. /* 
  1299.  * DoReceive
  1300.  */
  1301. static VOID 
  1302. DoReceive(struct AgnetDevUnit *adu, struct DelayRequest *delayed)
  1303. {
  1304.   ULONG length = delayed->dr_DataLen;
  1305.   ULONG type   = delayed->dr_PacketType;
  1306.   struct IOSana2Req *rxr;
  1307.  
  1308.   /* Update statistics */
  1309.   PacketReceived(adu, length, type);
  1310.   if (adu->adu_MaxTU < length) {
  1311.     PacketOverrun(adu);
  1312.     return;
  1313.   }
  1314.   if (adu->adu_MinTU > length) {
  1315.     ReceivedGarbage(adu);
  1316.     return;
  1317.   }
  1318.  
  1319.   /* Find an appropriate request wanting this packet type */
  1320.   LockUnit(adu);
  1321.  
  1322.   for (rxr = (struct IOSana2Req *)adu->adu_Rx.mlh_Head;
  1323.        rxr->ios2_Req.io_Message.mn_Node.ln_Succ; 
  1324.        rxr = (struct IOSana2Req *)rxr->ios2_Req.io_Message.mn_Node.ln_Succ) {
  1325.     if (rxr->ios2_PacketType == type) {
  1326.       Remove((struct Node *)rxr);
  1327.       CopyBack(adu, rxr, delayed);
  1328.       rxr = NULL;
  1329.       break;
  1330.     }
  1331.   }
  1332.  
  1333.   if (rxr) {
  1334.     /* Nobody wants this packet type? So, it's orphan */
  1335.     ReceivedOrphan(adu);
  1336.     if (rxr = (struct IOSana2Req *)
  1337.     RemHead((struct List *)&adu->adu_RxOrph)) {
  1338.       rxr -> ios2_PacketType = type;
  1339.       CopyBack(adu, rxr, delayed);
  1340.     } else {
  1341.       /* Nobody is interested in this packet, drop it */
  1342.       PacketDropped(adu, type);
  1343.     }
  1344.   }
  1345.   
  1346.   UnlockUnit(adu);
  1347. }
  1348.  
  1349. /*
  1350.  * Copy received packet into a request,
  1351.  * return the request to the caller
  1352.  */
  1353. static VOID
  1354. CopyBack(struct AgnetDevUnit *adu, struct IOSana2Req *ios2, 
  1355.      struct DelayRequest *delayed)
  1356. {
  1357.   struct BufferManagement * bm =
  1358.     (struct BufferManagement *)ios2->ios2_BufferManagement;
  1359.   void *data = delayed->dr_Data;
  1360.   ULONG length = delayed->dr_DataLen;
  1361.   WORD  adrlen = (adu->adu_AddrFieldSize + 7) >> 3;
  1362.  
  1363.   /* Copy the data into the protocol stack's buffer using its
  1364.      supplied callback routine. */
  1365.   if (bm->bm_CopyToBuffer &&
  1366.       (*bm->bm_CopyToBuffer)(ios2->ios2_Data, data, length)) {
  1367.     ios2->ios2_DataLength =    length;
  1368.  
  1369.     if (delayed->dr_Cmd == S2_BROADCAST) {
  1370.       ios2->ios2_Req.io_Flags |= SANA2IOB_BCAST;
  1371.       memset(ios2->ios2_DstAddr, 0xff, adrlen);
  1372.     } else {
  1373.       memcpy(ios2->ios2_DstAddr, adu->adu_Addr, adrlen);
  1374.     }
  1375.     memcpy(ios2->ios2_SrcAddr, delayed->dr_SrcAddr, adrlen); 
  1376.  
  1377.     TermIO(ios2);
  1378.     return;
  1379.   } else {
  1380.     ios2->ios2_DataLength   = 0;
  1381.     ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  1382.     ios2->ios2_WireError    = S2WERR_BUFF_ERROR;
  1383.     DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_RX | S2EVENT_BUFF | S2EVENT_ERROR);
  1384.     TermIO(ios2);
  1385.     return;
  1386.   }
  1387. }
  1388.  
  1389.  
  1390.